import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;


public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int choice;

        do {
            // 显示菜单
            System.out.println("\n请输入数字选择操作：");
            System.out.println("1. 查询股票信息 (m_stocks)");
            System.out.println("2. 查询分红记录 (divided_record)");
            System.out.println("3. 查询历史股价 (stocks_history)");
            System.out.println("4. 计算所有股票最新股息率(只输出股息率大于0的股票信息)");ex
            System.out.println("5. 对股息率进行排序并输出大于6的股票相关信息");
            System.out.println("0. 退出程序");
            System.out.print("请输入选项: ");

            // 读取用户输入
            try {
                choice = Integer.parseInt(scanner.nextLine());
            } catch (NumberFormatException e) {
                System.out.println("输入错误，请输入数字！");
                choice = -1; // 设置为无效选项
                continue;
            }

            // 根据输入执行操作
            switch (choice) {
                case 1:
                    queryStocks();
                    break;
                case 2:
                    queryDividendRecords();
                    break;
                case 3:
                    queryStockHistory();
                    break;
                case 4:
                    calculateDividendYield();
                    break;
                case 5:
                    sortcalculateDividendYiele();
                    break;
                case 0:
                    System.out.println("程序已退出。");
                    break;
                default:
                    System.out.println("无效选项，请重新输入！");
            }
        } while (choice != 0); // 输入 0 时退出循环

        scanner.close();
    }

    private static void sortcalculateDividendYiele() {
        String dividendSql = "SELECT d.stock_code, s.stock_nm, d.dividend " +
                "FROM divided_record d " +
                "JOIN m_stocks s ON d.stock_code = s.stock_code " +
                "WHERE (d.stock_code, d.announcement_date) IN (" +
                "    SELECT stock_code, MAX(announcement_date) " +
                "    FROM divided_record " +
                "    GROUP BY stock_code" +
                ")";

        String priceSql = "SELECT h.stock_code, h.close_price " +
                "FROM stocks_history h " +
                "WHERE (h.stock_code, h.trade_date) IN (" +
                "    SELECT stock_code, MAX(trade_date) " +
                "    FROM stocks_history " +
                "    GROUP BY stock_code" +
                ")";

        // 定义承载结果的临时类
        class StockYieldInfo {
            String stockCode;
            String stockNm;
            BigDecimal dividendPerShare;
            BigDecimal closePrice;
            BigDecimal yieldRate;

            StockYieldInfo(String stockCode, String stockNm, BigDecimal dividendPerShare,
                           BigDecimal closePrice, BigDecimal yieldRate) {
                this.stockCode = stockCode;
                this.stockNm = stockNm;
                this.dividendPerShare = dividendPerShare;
                this.closePrice = closePrice;
                this.yieldRate = yieldRate;
            }
        }

        List<StockYieldInfo> yieldList = new ArrayList<>();

        try (Connection con = DBUtils.getConnection();
             PreparedStatement pstmtDividend = con.prepareStatement(dividendSql);
             ResultSet rsDividend = pstmtDividend.executeQuery()) {

            Map<String, String> stockNmMap = new HashMap<>();
            Map<String, BigDecimal> dividendMap = new HashMap<>();
            while (rsDividend.next()) {
                String stockCode = rsDividend.getString("stock_code");
                String stockNm = rsDividend.getString("stock_nm");
                String dividendStr = rsDividend.getString("dividend");
                BigDecimal dividendPerShare = parseDividend(dividendStr);
                stockNmMap.put(stockCode, stockNm);
                dividendMap.put(stockCode, dividendPerShare);
            }

            try (PreparedStatement pstmtPrice = con.prepareStatement(priceSql);
                 ResultSet rsPrice = pstmtPrice.executeQuery()) {

                Map<String, BigDecimal> priceMap = new HashMap<>();
                while (rsPrice.next()) {
                    String stockCode = rsPrice.getString("stock_code");
                    BigDecimal closePrice = new BigDecimal(rsPrice.getString("close_price"));
                    priceMap.put(stockCode, closePrice);
                }

                // 计算股息率并填充列表
                for (String stockCode : dividendMap.keySet()) {
                    BigDecimal dividend = dividendMap.get(stockCode);
                    BigDecimal price = priceMap.getOrDefault(stockCode, BigDecimal.ZERO);

                    if (price.compareTo(BigDecimal.ZERO) != 0 && dividend.compareTo(BigDecimal.ZERO) > 0) {
                        BigDecimal yield = dividend.divide(price, 4, RoundingMode.HALF_UP)
                                .multiply(new BigDecimal("100"));
                        yieldList.add(new StockYieldInfo(
                                stockCode,
                                stockNmMap.get(stockCode),
                                dividend,
                                price,
                                yield
                        ));
                    }
                }
            }

        } catch (SQLException e) {
            throw new RuntimeException("数据库查询失败", e);
        }

        // 排序和筛选
        yieldList.sort((a, b) -> b.yieldRate.compareTo(a.yieldRate)); // 从高到低排序
        List<StockYieldInfo> filteredList = yieldList.stream()
                .filter(info -> info.yieldRate.compareTo(new BigDecimal("6")) > 0)
                .collect(Collectors.toList());

        // 输出结果
        System.out.println("\n股票代码\t股票名称\t最新股息(元/股)\t最新收盘价\t股息率(%)");
        if (filteredList.isEmpty()) {
            System.out.println("没有找到股息率 >6% 的股票");
        } else {
            filteredList.forEach(info ->
                    System.out.printf("%s\t%-10s\t%-10.4f\t%-10.2f\t%-6.2f%%\n",
                            info.stockCode,
                            info.stockNm,
                            info.dividendPerShare,
                            info.closePrice,
                            info.yieldRate)
            );
        }
    }


    // 辅助类和方法
    private static class DividendData {
        String stockNm;
        BigDecimal dividendPerShare;

        DividendData(String stockNm, BigDecimal dividendPerShare) {
            this.stockNm = stockNm;
            this.dividendPerShare = dividendPerShare;
        }
    }

    private static void calculateDividendYield() {
        // 修正后的SQL：获取每个股票的最新分红记录
        String dividendSql = "SELECT d.stock_code, s.stock_nm, d.dividend " +
                "FROM divided_record d " +
                "JOIN m_stocks s ON d.stock_code = s.stock_code " +
                "WHERE (d.stock_code, d.announcement_date) IN (" +
                "    SELECT stock_code, MAX(announcement_date) " +
                "    FROM divided_record " +
                "    GROUP BY stock_code" +
                ")";

        // 修正后的SQL：获取每个股票的最新收盘价
        String priceSql = "SELECT h.stock_code, h.close_price " +
                "FROM stocks_history h " +
                "WHERE (h.stock_code, h.trade_date) IN (" +
                "    SELECT stock_code, MAX(trade_date) " +
                "    FROM stocks_history " +
                "    GROUP BY stock_code" +
                ")";

        Map<String, DividendData> dividendMap = new HashMap<>();
        Map<String, BigDecimal> priceMap = new HashMap<>();

        try (Connection con = DBUtils.getConnection();
             PreparedStatement pstmtDividend = con.prepareStatement(dividendSql);
             ResultSet rsDividend = pstmtDividend.executeQuery()) {

            // 解析分红数据
            while (rsDividend.next()) {
                String stockCode = rsDividend.getString("stock_code");
                String stockNm = rsDividend.getString("stock_nm");
                String dividendStr = rsDividend.getString("dividend");
                BigDecimal dividendPerShare = parseDividend(dividendStr);
                dividendMap.put(stockCode, new DividendData(stockNm, dividendPerShare));
            }

        } catch (SQLException e) {
            throw new RuntimeException("分红数据查询失败", e);
        }

        try (Connection con = DBUtils.getConnection();
             PreparedStatement pstmtPrice = con.prepareStatement(priceSql);
             ResultSet rsPrice = pstmtPrice.executeQuery()) {

            // 解析股价数据
            while (rsPrice.next()) {
                String stockCode = rsPrice.getString("stock_code");
                BigDecimal closePrice = new BigDecimal(rsPrice.getString("close_price"));
                priceMap.put(stockCode, closePrice);
            }

        } catch (SQLException e) {
            throw new RuntimeException("股价数据查询失败", e);
        }

        // 计算并输出股息率
        System.out.println("\n股票代码\t股票名称\t最新股息(元/股)\t最新收盘价\t股息率(%)");
        dividendMap.forEach((stockCode, dividendData) -> {
            BigDecimal closePrice = priceMap.getOrDefault(stockCode, BigDecimal.ZERO);
            if (closePrice.compareTo(BigDecimal.ZERO) == 0) {
                System.out.printf("%s\t%s\t%.4f\t无最新股价\tN/A\n",
                        stockCode, dividendData.stockNm, dividendData.dividendPerShare);
            } else {
                BigDecimal yield = dividendData.dividendPerShare
                        .divide(closePrice, 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100"));
                if(!dividendData.dividendPerShare.equals(BigDecimal.ZERO)){
                    System.out.printf("%s\t%s\t%.4f\t\t\t%.2f\t\t%.2f%%\n",
                            stockCode, dividendData.stockNm, dividendData.dividendPerShare, closePrice, yield);
                }
            }
        });
    }

    // 修复后的分红解析方法
    private static BigDecimal parseDividend(String dividendStr) {
        if (dividendStr == null || dividendStr.isEmpty() || dividendStr.equals("--") || dividendStr.equals("不分配不转增")) {
            return BigDecimal.ZERO;
        }
        // 处理 "每10股派1.45元" 或 "10派1.45元" 格式
        String[] parts = dividendStr.split("派");
        if (parts.length < 2) return BigDecimal.ZERO;

        // 提取总派息金额（例如 "1.45元" -> 1.45）
        String totalStr = parts[1].replaceAll("[^0-9.]", "");
        if (totalStr.isEmpty()) return BigDecimal.ZERO;
        BigDecimal total = new BigDecimal(totalStr);

        // 提取每股基数（例如 "每10股" -> 10，默认为10股）
        String baseStr = parts[0].replaceAll("[^0-9.]", "");
        BigDecimal base = baseStr.isEmpty() ? BigDecimal.TEN : new BigDecimal(baseStr);

        // 计算每股分红：总派息金额 / 基数
        return total.divide(base, 4, RoundingMode.HALF_UP);
    }



    private static void queryStocks() {
        String sql = "SELECT * FROM m_stocks";
        List<Stock> stockList = new ArrayList<>();

        try (
                Connection con = DBUtils.getConnection();
                PreparedStatement pstam = con.prepareStatement(sql);
                ResultSet rs = pstam.executeQuery()
        ) {
            while (rs.next()) {
                String updatedBy = rs.getString("updated_by");
                String stockCode = rs.getString("stock_code");
                String stockNm = rs.getString("stock_nm");
                String exChange = rs.getString("exchange");
                String exchangeShort = rs.getString("exchange_short");
                String deprecatedFlg = rs.getString("deprecated_flg");
                String indexDate = rs.getString("index_date");
                String createTime = rs.getString("create_time");
                String createdBy = rs.getString("created_by");
                String updateTime = rs.getString("update_time");

                Stock stock = new Stock(updatedBy, stockCode, stockNm, exChange, exchangeShort, deprecatedFlg, indexDate, createTime, createdBy, updateTime);
                stockList.add(stock);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        for (Stock stock : stockList) {
            System.out.println(stock);
        }
    }

    private static void queryDividendRecords() {
        String sql = "SELECT * FROM divided_record";
        List<DividendRecord> dividendRecordList = new ArrayList<>();

        try (
                Connection con = DBUtils.getConnection();
                PreparedStatement pstam = con.prepareStatement(sql);
                ResultSet rs = pstam.executeQuery()
        ) {
            while (rs.next()) {
                String stockCode = rs.getString("stock_code");
                String announcementDate = rs.getString("announcement_date");
                String dividend = rs.getString("dividend");
                String recordDate = rs.getString("record_date");
                String exDate = rs.getString("ex_date");
                String datePayable = rs.getString("date_payable");
                String progress = rs.getString("progress");
                String createTime = rs.getString("create_time");
                String createdBy = rs.getString("created_by");
                String updatedBy = rs.getString("updated_by");
                String updateTime = rs.getString("update_time");

                DividendRecord dividendRecord = new DividendRecord(stockCode, announcementDate, dividend, recordDate, exDate, datePayable, progress, createTime, createdBy, updatedBy, updateTime);
                dividendRecordList.add(dividendRecord);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        for (DividendRecord dividendRecord : dividendRecordList) {
            System.out.println(dividendRecord);
        }
    }

    private static void queryStockHistory() {
        String sql = "SELECT * FROM stocks_history";
        List<StockHistory> stockHistoryList = new ArrayList<>();

        try (
                Connection con = DBUtils.getConnection();
                PreparedStatement pstam = con.prepareStatement(sql);
                ResultSet rs = pstam.executeQuery()
        ) {
            while (rs.next()) {
                String stockCode = rs.getString("stock_code");
                String tradeDate = rs.getString("trade_date");
                String stockNm = rs.getString("stock_nm");
                String closePrice = rs.getString("close_price");
                String createdBy = rs.getString("created_by");
                String createTime = rs.getString("create_time");
                String updatedBy = rs.getString("updated_by");
                String updateTime = rs.getString("update_time");

                StockHistory stockHistory = new StockHistory(stockCode, tradeDate, stockNm, closePrice, createdBy, createTime, updatedBy, updateTime);
                stockHistoryList.add(stockHistory);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        for (StockHistory stockHistory : stockHistoryList) {
            System.out.println(stockHistory);
        }
    }
}